package nz.co.listit.hailacabprototype;

import java.net.URI;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.utils.URIUtils;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.json.JSONException;
import org.json.JSONObject;
import android.util.Log;

public class ListItServerClient {
	private static int TIMEOUT_CONNECTION = 10000; // 20 sec
	private static int TIMEOUT_SOCKET = 10000;  // 20 sec
	
	protected static final String MASTER_PWD = "mini426kaniko"; // do not share!!!
	
	public static String LISTIT_SERVICE = "www.list-it.co.nz/dev/SmartService.svc";
	//public static final String LISTIT_SERVICE = "192.168.1.250/dev/SmartService.svc/";
	public static final String RET_CODE             = "return_code";
	public static final String RET_MESSAGE          = "message";
	public static final String RET_HTTP_STATUS_CODE = "http_status_code";
	
	/**
	 *  To convert the InputStream to String we use the BufferedReader.readLine()
	 * method. We iterate until the BufferedReader return null which means
	 * there's no more data to read. Each line will appended to a StringBuilder
	 * and returned as String.
	 * @param stream
	 * @return
	 */
	private String convertStreamToString(InputStream stream) {
		/*
		 
		 */
		BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
		StringBuilder sb = new StringBuilder();

		String line = null;
		try {
			while ((line = reader.readLine()) != null) {
				sb.append(line + "\n");
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				stream.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}

		return sb.toString();
	}
	
	/**
	 * This functions encrypts the query parameters that we are going to send to the
	 * server 
	 * @param qparams: contains list of all parameters and values
	 * @return encrypted query string
	 */
	private String getEncryptedQueryString(List<NameValuePair> qparams)
	{
		List<NameValuePair> encryptedParams = new ArrayList<NameValuePair>();
		SimpleCrypto crypto = new SimpleCrypto(MASTER_PWD);
		
		for (int i = 0; i < qparams.size(); i++) {
			encryptedParams.add(new BasicNameValuePair(qparams.get(i).getName(), 
				crypto.encryptAsBase64(qparams.get(i).getValue().getBytes())));
		}
		
		return URLEncodedUtils.format(encryptedParams, "UTF-8");
	}
	
	/**
	 * This function queries List-It service and returns the value as a JSONObject
	 * @param actionName: the name of the ListIt web service action
	 * @return JSONObject
	 */
	public JSONObject queryListItService(String path, List<NameValuePair> qparams) {
		String rawResult = "";
			
		
		try {
			HttpResponse response = makeRequest(path, qparams);
			
			HttpEntity entity = response.getEntity();
			
			if (entity != null) {
				InputStream instream = entity.getContent();
				rawResult = this.convertStreamToString(instream);
				Log.i("result", rawResult);
				instream.close();
				
				// now strip out the 'd'
				JSONObject dJSON = new JSONObject(rawResult);
				String pathStr = dJSON.get("d").toString();
				
				// get path JSON
				JSONObject pathJSON = new JSONObject(pathStr);
				String result = pathJSON.getString(path);
				
				return new JSONObject(result); 
			}
		} catch (ClientProtocolException e) {
			Log.e("REST", "There was a protocol based error", e);
		} catch (IOException e) {
			// the string is not in a valid json format. Beautify it then return
			JSONObject jsonObj = new JSONObject();
			try {
				jsonObj.put(RET_MESSAGE, e.toString());
				jsonObj.put("return_code", WEBSERVER_MESSAGES.CONNECTION_ERROR.ordinal());
				return jsonObj;
			}
			catch (JSONException e1) {
				// this should not happen
				e1.printStackTrace();
			}

		} catch (JSONException e) {
			Log.e("JSON", "String is not a valid JSON format", e);
			
			// the string is not in a valid json format. Beautify it then return
			JSONObject jsonObj = new JSONObject();
			try {
				if (rawResult.contains("404 Not Found"))
					//jsonObj.put(RET_MESSAGE, getString(R.string.not_found_error));
					jsonObj.put(RET_MESSAGE, "404 Not Found");
				else
					jsonObj.put(RET_MESSAGE, rawResult);
				
				jsonObj.put("return_code", WEBSERVER_MESSAGES.CONNECTION_ERROR.ordinal());
				
				return jsonObj;
			} catch (JSONException e1) {
				// this should not happen
				e1.printStackTrace();
			}
			
			return jsonObj;
		} catch (URISyntaxException e) {
			Log.e("UIR", "Invalid URI syntax", e);
		}
		
		return null;
	}
	// see http://androidsnippets.com/retrieve-json-from-a-rest-web-service
	
	public HttpResponse makeRequest(String path, List<NameValuePair> qparams) 
			throws ClientProtocolException, IOException, URISyntaxException {
		
		String encryptedQueryParam = getEncryptedQueryString(qparams);
	
		HttpParams httpParameters = new BasicHttpParams();
		// Set the timeout in milliseconds until a connection is established.
		HttpConnectionParams.setConnectionTimeout(httpParameters, TIMEOUT_CONNECTION);
		HttpConnectionParams.setSoTimeout(httpParameters, TIMEOUT_SOCKET);

		HttpClient httpclient = new DefaultHttpClient(httpParameters);
		URI uri = null;
		
		uri = URIUtils.createURI("http", LISTIT_SERVICE, -1, path, encryptedQueryParam, null);
		
		HttpGet httpget = new HttpGet(uri);

		Log.i("URI", httpget.getURI().toString());

		return httpclient.execute(httpget);
	}
}
